import SparkMD5 from 'spark-md5'
import {
  uploadChunkUsingPost,
  mergeChunkUsingPost,
  uploadBase64ImageUsingPost
} from '@/api/fileController'
import { ref } from 'vue'
import { Notification } from '@arco-design/web-vue'
import {
  IconFile,
  IconImage,
  IconMusic,
  IconFile as IconVideo,
  IconFile as IconFileWord,
  IconFile as IconFileExcel,
  IconFile as IconFilePdf,
  IconFile as IconFileZip,
  IconCode,
  IconFile as IconFileText
} from '@arco-design/web-vue/es/icon'
// 文件上传工具类
const CHRUNK_SIZE = 1024 * 1024 * 5 //分片大小
const MAX_REQUEST_NUM = 4
let activePromises = []
let progress = 0
let completedCount = ref(0) // 已完成的分片数量
const totalChunks = ref(0)
//大文件上传文件
export const uploadBigFile = async (file, onProgress) => {
  const chunks = createChunk(file)
  const fileMd5 = await calcHash(chunks)
  const fileUrl = await uploadChunks(file.name, chunks, fileMd5, MAX_REQUEST_NUM, onProgress)
  return fileUrl
}
// 创建分片
const createChunk = (file) => {
  let cur = 0
  let chunks = []
  while (cur < file.size) {
    const blob = file.slice(cur, cur + CHRUNK_SIZE)
    chunks.push(blob)
    cur += CHRUNK_SIZE
  }
  return chunks
}
//计算hash
const calcHash = (chunks) => {
  const targets = []
  let md5
  const spark = new SparkMD5.ArrayBuffer()
  const fileReader = new FileReader()
  // 为了计算hash更快，截取部分文件片
  chunks.forEach((chunck, index) => {
    if (index === 0 || index === chunks.length - 1) {
      targets.push(chunck)
    } else {
      targets.push(chunck.slice(0, 2))
      targets.push(chunck.slice(CHRUNK_SIZE / 2, CHRUNK_SIZE / 2 + 2))
      targets.push(chunck.slice(CHRUNK_SIZE - 2, CHRUNK_SIZE))
    }
  })
  // 好扭比的普绕米斯 令我文件上传爆肥
  return new Promise((resolve, reject) => {
    fileReader.readAsArrayBuffer(new Blob(targets))

    fileReader.onload = (e) => {
      spark.append(e.target.result)
      const md5 = spark.end()
      resolve(md5) // 成功时返回md5值
    }

    fileReader.onerror = (err) => {
      reject(err) // 失败时抛出错误
    }
  })
}
// 分片上传
const uploadChunks = async (fileName, chunks, fileMd5, MAX_REQUEST_NUM = 4, onProgress) => {
  const formDatas = chunks.map((chunk, index) => {
    const formData = new FormData()
    formData.append('fileName', fileName)
    formData.append('fileMd5', fileMd5)
    formData.append('chunkMd5', `${fileMd5}-${index}`)
    formData.append('chunk', chunk)
    return formData
  })
  totalChunks.value = formDatas.length
  for (let i = 0; i < formDatas.length; i++) {
    await uploadNext(i, formDatas[i], formDatas.length, onProgress)
    if (i >= formDatas.length - 1) {
      // 所有分片都已上传
      await Promise.all(activePromises) // 等待所有剩余的活动 Promise 完成（理论上应该是空的）
      // 合并分片
      const mergeChunkUsingPostDto = { fileName, fileMd5 }
      const fileUrl = await mergeChunkUsingPost(mergeChunkUsingPostDto)
      completedCount.value = 0
      totalChunks.value = 0
      return fileUrl
    }
  }
}

const uploadNext = async (i, formData, maxLength, onProgress) => {
  const promise = uploadChunkUsingPost(formData).finally(() => {
    // 从活动 Promise 数组中移除这个 Promise
    const indexToRemove = activePromises.findIndex((p) => p === promise)
    if (indexToRemove !== -1) {
      activePromises.splice(indexToRemove, 1)
    }
    // 上传完成后更新进度条
    completedCount.value++
    progress = Number(Math.round((completedCount.value / totalChunks.value) * 100).toFixed(2))
    if (onProgress) {
      onProgress(progress)
    }
  })
  // 将这个 Promise 添加到活动 Promise 数组中
  activePromises.push(promise)
  if (activePromises.length > MAX_REQUEST_NUM) {
    await Promise.race(activePromises.map((p) => p.finally(() => false)))
  }
}

//获取numFrames视频封面数
/**
 *
 * @param {string} url
 * @param {number} width
 * @param {number} height
 * @param {number} numFrames
 * @returns
 */
export const getVideoCovers = async (url, width = 1920, height = 1080, numFrames = 5) => {
  return new Promise((resolve, reject) => {
    const covers = []
    const video = document.createElement('video')
    video.src = url // 视频播放地址
    const canvas = document.createElement('canvas')
    canvas.width = width
    canvas.height = height
    const ctx = canvas.getContext('2d')
    video.crossOrigin = 'anonymous' // 解决跨域问题

    video.onloadedmetadata = () => {
      const duration = video.duration // 获取视频总时长
      const interval = duration / numFrames // 计算每个截图的时间间隔

      let frameIndex = 0

      const captureFrame = () => {
        if (frameIndex >= numFrames) {
          video.remove()
          canvas.remove()
          resolve(covers)
          return
        }
        video.currentTime = frameIndex * interval // 设置当前时间为下一个截图时间点
      }
      video.onseeked = async () => {
        ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
        const base64Cover = canvas.toDataURL('image/png') // 获取base64格式的图片
        covers.push(base64Cover)
        frameIndex++
        captureFrame() // 捕获下一帧
      }

      video.onerror = (error) => {
        console.error('Error loading video:', error)
        video.remove()
        canvas.remove()
        reject(error)
      }

      captureFrame() // 开始捕获第一帧
    }

    video.onerror = (error) => {
      console.error('Error loading video:', error)
      video.remove()
      canvas.remove()
      reject(error)
    }
  })
}
// 获取视频时长
export const getVideoDuration = (url) => {
  return new Promise((resolve) => {
    const video = document.createElement('video')
    video.src = url
    // 监听元数据加载完成事件
    video.onloadedmetadata = () => {
      // duration是以秒为单位的浮点数
      const duration = Math.floor(video.duration * 1000)
      resolve(duration)
    }
    // 处理可能的错误
    video.onerror = () => {
      console.error('Failed to load video metadata')
      resolve(0)
    }
  })
}

// 格式化文件大小
export const formatFileSize = (bytes) => {
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// 文件下载
export const downloadFile = async (file) => {
  try {
    // 发起请求获取文件流
    const response = await fetch(file.url)
    const blob = await response.blob()

    // 创建 Blob URL
    const url = window.URL.createObjectURL(blob)

    // 创建一个 a 标签
    const link = document.createElement('a')
    link.href = url
    link.download = file.name // 设置下载文件名

    // 添加到 body 中
    document.body.appendChild(link)

    // 触发点击
    link.click()

    // 移除 a 标签
    document.body.removeChild(link)

    // 释放 Blob URL
    window.URL.revokeObjectURL(url)

    Notification.info('开始下载文件')
  } catch (error) {
    Notification.error('下载失败：' + error)
  }
}
/**
 * 获取文件图标
 * @param {string} fileName 文件名
 * @returns {string} 文件图标
 */
export const getFileIcon = (fileName) => {
  const extension = fileName.split('.').pop()?.toLowerCase()

  // 图片文件
  if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(extension || '')) {
    return IconImage
  }

  // 音频文件
  if (['mp3', 'wav', 'ogg', 'flac', 'm4a'].includes(extension || '')) {
    return IconMusic
  }

  // 视频文件
  if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'].includes(extension || '')) {
    return IconVideo
  }

  // Word文档
  if (['doc', 'docx'].includes(extension || '')) {
    return IconFileWord
  }

  // Excel文档
  if (['xls', 'xlsx'].includes(extension || '')) {
    return IconFileExcel
  }

  // PDF文档
  if (extension === 'pdf') {
    return IconFilePdf
  }

  // 压缩文件
  if (['zip', 'rar', '7z', 'tar', 'gz'].includes(extension || '')) {
    return IconFileZip
  }

  // 代码文件
  if (['js', 'ts', 'html', 'css', 'java', 'py', 'php', 'cpp', 'c', 'h'].includes(extension || '')) {
    return IconCode
  }

  // 文本文件
  if (['txt', 'md', 'json', 'xml', 'log'].includes(extension || '')) {
    return IconFileText
  }

  // 默认文件图标
  return IconFile
}
/**
 * 获取文件类型
 * @param {string} extension 文件扩展名
 * @returns {string} 文件类型
 */
export const getFileType = (extension) => {
  if (!extension) return 'other'

  // 图片文件
  if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(extension)) {
    return 'image'
  }

  // PDF文件
  if (extension === 'pdf') {
    return 'pdf'
  }

  // Markdown文件
  if (extension === 'md') {
    return 'markdown'
  }

  // 文本文件
  if (['txt', 'json', 'xml', 'log'].includes(extension)) {
    return 'text'
  }

  // Office文件
  if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(extension)) {
    return 'office'
  }

  return 'other'
}
/**
 * 判断是否为图片文件
 * @param {string} fileName 文件名
 * @returns {boolean} 是否为图片文件
 */
export const isImageFile = (fileName) => {
  const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
  return imageExtensions.some((ext) => fileName.toLowerCase().endsWith(ext))
}
